﻿using DataGrab;
using HtmlAgilityPack;
using JingBaiHui.Common;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace DianPingDataGrab.Provider
{
    public class DianPingProvider
    {
        public DataTable DtResult = new DataTable();
        private static readonly object lockObj = new object();

        public static List<string> TitleXPath = new List<string>() {
            "//*[@id=\"basic-info\"]/h1",
            "//*[@id=\"J_boxDetail\"]/div/div[1]/h1",
            "//*[@id=\"poi-detail\"]/div[2]/div[1]/div[2]/div[1]/div[1]/div[1]/div/h1",
            "//*[@id=\"top\"]/div[5]/div/div[1]/div[1]/div[1]/h1",
            "//*[@id=\"poi-detail\"]/div[2]/div[1]/div[1]/div[1]/div[1]/div[1]/div/h1",
            "//*[@id=\"J_boxPromo\"]/div/h1",
            "//*[@id=\"top\"]/div[4]/div[1]/div[1]/div/div[1]/h1",
        };

        public static List<string> AddressXPath = new List<string>() {
            "//*[@id=\"basic-info\"]/div[2]/span[2]",
            "//*[@id=\"J_boxDetail\"]/div/div[3]/div/span[2]",
            "//*[@id=\"poi-detail\"]/div[2]/div[1]/div[2]/div[1]/div[1]/div[2]/div[1]/span[1]",
            "//*[@id=\"top\"]/div[5]/div/div[1]/div[1]/div[2]/div[2]/div[2]",
            "//*[@id=\"poi-detail\"]/div[2]/div[1]/div[1]/div[1]/div[1]/div[2]/div[1]/span[1]",
            "//*[@id=\"J_boxPromo\"]/div/div[2]/div/span",
            "//*[@id=\"top\"]/div[4]/div[1]/div[1]/div/div[3]/dl[1]/dd/span[1]"
        };

        public static List<string> PhoneXPath = new List<string>()
        {
            "//*[@id=\"basic-info\"]/p/span[2]",
            "//*[@id=\"J_boxYouhui\"]/div[4]/span[1]",
            "//*[@id=\"poi-detail\"]/div[2]/div[1]/div[2]/div[1]/div[1]/div[1]/div/div[1]/div/span[2]",
            "//*[@id=\"top\"]/div[5]/div/div[1]/div[1]/div[2]/div[2]/div[4]/div/span",
            "//*[@id=\"J_boxPromo\"]/div/p",
            "//*[@id=\"J-showPhoneNumber\"]"
        };

        public DianPingProvider()
        {
            //名称，联系人，电话，地址，区域
            DataTable dt = DtResult;
            dt.Columns.Add("区域");
            dt.Columns.Add("名称");
            dt.Columns.Add("电话");
            dt.Columns.Add("地址");
            dt.Columns.Add("链接");

        }
        private void SetLog(string msg)
        {
            Console.WriteLine(msg);
        }

        private DataTable GetMainTable()
        {
            //名称，联系人，电话，地址，区域
            DataTable dt = new DataTable();
            dt.Columns.Add("区域");
            dt.Columns.Add("名称");
            dt.Columns.Add("电话");
            dt.Columns.Add("地址");
            dt.Columns.Add("链接");
            return dt;
        }


        public void SearchData()
        {
            DtResult.Rows.Clear();

            SetLog("开始同步获取区域链接.....");
            var areaLinks = GetAreaLinks();
            SetLog($"区域链接获取成功，共获取区域链接 {areaLinks.Count} 个");
            foreach (var item in areaLinks)
            {
                SearchArea(item.Key, item.Value);
            }
        }

        private void SearchArea(string areaName, string areaLink)
        {
            string domianUrl = "http://www.dianping.com";

            int pageCount = 50;
            for (int i = 1; i <= pageCount; i++)
            {
                string areaPageUrl = areaLink + "p" + i;
                var html = HttpHelper.Request(areaPageUrl, null, RestSharp.Method.GET);
                if (string.IsNullOrWhiteSpace(html))
                    continue;

                var doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(html);
                var mainNode = doc.DocumentNode.SelectSingleNode("//*[@id=\"shop-all-list\"]/ul");
                if (mainNode == null)
                    continue;

                var liNodes = mainNode.ChildNodes.Where(t => t.Name.Equals("li")).ToList();
                for (int j = 0; j < liNodes.Count; j++)
                {
                    try
                    {
                        var href = liNodes[j].ChildNodes.FirstOrDefault(t => t.OuterHtml.Contains("class=\"pic\"")).ChildNodes.FirstOrDefault(t => t.Name.Equals("a")).Attributes["href"].Value;
                        var shopName = liNodes[j].ChildNodes[3].InnerText.Replace("\n", "").Replace("\r", "").Trim();
                        href = domianUrl + href;
                        //SetLog($"详情页链接 {href} 获取成功！开始抓取详细内容...");
                        Task.Factory.StartNew(() =>
                        {
                            try
                            {
                                GrabDetailPage(href, areaName);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("【抓取异常】，" + ex.Message);
                                lock (lockObj)
                                {
                                    JingBaiHui.Common.LogHelper.Error(ex, $"href:{href},{ex.Message}");
                                }
                            }
                        });
                    }
                    catch (Exception ex)
                    {
                        SetLog($"{areaName},链接：{areaPageUrl} 第{j}条的详情页解析失败！msg:{ex.Message}");
                    }
                }
            }
        }

        private HtmlNode GetNodeByXPath(HtmlDocument doc, string nodeName)
        {
            var xpathList = new List<string>();
            switch (nodeName)
            {
                case "AddressXPath":
                    xpathList = AddressXPath;
                    break;
                case "PhoneXPath":
                    xpathList = PhoneXPath;
                    break;
                case "TitleXPath":
                default:
                    xpathList = TitleXPath;
                    break;
            }
            foreach (var item in xpathList)
            {
                var node = doc.DocumentNode.SelectSingleNode(item);
                if (node != null)
                    return node;
            }
            return null;
        }

        public void GrabDetailPage(string url, string areaName)
        {
            var html = HttpHelper.Request(url, null, RestSharp.Method.GET);
            if (string.IsNullOrWhiteSpace(html))
                return;

            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);
            var titleNode = GetNodeByXPath(doc, "TitleXPath");
            var addressNode = GetNodeByXPath(doc, "AddressXPath");
            var phoneNode = GetNodeByXPath(doc, "PhoneXPath");

            DataRow dr = DtResult.NewRow();
            dr["区域"] = areaName;
            dr["名称"] = TrimOther(titleNode.FirstChild.InnerText);

            if (phoneNode != null)
            {
                var phone = string.Empty;
                if (phoneNode.InnerText.Contains("*"))
                    phone = phoneNode.GetAttributeValue("data-phone", string.Empty);
                else if (phoneNode.InnerText.Contains("查看完整号码"))
                    phone = phoneNode.GetAttributeValue("data-real", string.Empty);
                else
                    phone = phoneNode.InnerText;

                dr["电话"] = TrimOther(phone);
            }
            if (addressNode != null)
                dr["地址"] = TrimOther(addressNode.InnerText);

            dr["链接"] = url;

            string checkSql = $@"
select count(0) from [dbo].[DianPing] where Name='{dr["名称"]}'
";
            var count = SqlHelper.GetScalar(checkSql);
            if (count != "0")
            {
                string error = string.Empty;
                string sql = $@"
INSERT INTO [dbo].[DianPing]
           ( 
            [Name]
           ,[Phone]
           ,[Address]
           ,[Area]
           ,[Link])
     VALUES
           ( 
            '{dr["名称"]}'
           ,'{dr["电话"]}'
           ,'{dr["地址"]}'
           ,'{dr["区域"]}'
           ,'{dr["链接"]}')
";
                if (SqlHelper.ExecuteSql(sql, ref error))
                {
                    SetLog($"【抓取成功】，成功抓取数据{dr["名称"]}");
                }
                else
                {
                    Console.WriteLine("【抓取异常】，" + error);
                }
            }
            else
            {
                Console.WriteLine($"【自动跳过】，数据库已存在{dr["名称"]}的数据");
            }
            //SetLog(txtLog, $"当前已抓取 {grid.Rows.Count} 条数据");

        }

        private string TrimOther(string result)
        {
            return result.Replace("\n", string.Empty).Replace("\r", string.Empty).Trim();
        }
        private Dictionary<string, string> GetAreaLinks()
        {
            var areaUrls = new Dictionary<string, string>();
            string domianUrl = "http://www.dianping.com";
            string url = "http://www.dianping.com/shopall/344/0#BDBlock";
            var html = HttpHelper.Request(url, null, RestSharp.Method.GET);
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);
            var mainNode = doc.DocumentNode.SelectSingleNode("//*[@id=\"top\"]/div[6]/div/div[2]");
            var areaNodes = mainNode.ChildNodes.Where(t => t.InnerHtml.Contains("class=\"Bravia\"")).ToList();
            for (int i = 0; i < areaNodes.Count; i++)
            {
                var areaNode = areaNodes[i];
                var ddNode = areaNode.ChildNodes.FirstOrDefault(t => t.Name.Equals("dd"));
                if (ddNode != null)
                {
                    var ulNode = ddNode.ChildNodes.FirstOrDefault(t => t.Name.Equals("ul"));
                    if (ulNode != null)
                    {
                        var liNodes = ulNode.ChildNodes.Where(t => t.Name.Equals("li")).ToList();
                        for (int h = 0; h < liNodes.Count; h++)
                        {
                            var aNode = liNodes[h].ChildNodes.FirstOrDefault(t => t.Name.Equals("a"));
                            var href = domianUrl + aNode.Attributes["href"].Value;
                            var areaName = areaNode.ChildNodes[1].InnerText + "-" + aNode.InnerText;
                            //SetLog(txtLog, $"已获取区域：{areaName}，链接:{href}");
                            //if (areaName.Contains("长沙县") ||
                            //    areaName.Contains("芙蓉区") ||
                            //    areaName.Contains("雨花区"))
                            //{
                            //    areaUrls.Add(areaName, href);
                            //}

                            areaUrls.Add(areaName, href);
                        }
                    }
                }
            }
            return areaUrls;
        }
    }
}
